package show.me.the.money.accredit;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.web.context.WebApplicationContext;

import show.me.the.money.config.schema.Schema;
import show.me.the.money.config.schema.SchemaController;
import show.me.the.money.config.schema.SchemaItem;
import show.me.the.money.dao.QueryResult;
import show.me.the.money.dao.SimpleDAO;
import show.me.the.money.dao.exception.DataAccessException;
import show.me.the.money.util.AppContextHolder;
import show.me.the.money.util.context.Context;



@SuppressWarnings("unchecked")
public class DatabaseUserLoader {
	private static Log logger = LogFactory.getLog(DatabaseUserLoader.class);
	
	private static ObjectMapper jsonMapper = new ObjectMapper();
	public static final String entryName = "SYS_USERS";
	public static final String fieldRole = "jobId";
	public static final String fieldUserId = "userId"; //*
	public static final String fieldUserName = "name";
	public static final String fieldPassword = "password";
	public static final String fieldVersion = "userVersion";
	static String hql = "from " +  entryName + " where " + fieldUserId + "=:uid";
	
	public static Document getUserDoc(String id){
		HashMap<String,Object> rec = getUserById(id);
		if(rec != null){
			Document doc = getUserXMLTemplate(rec);
			return doc;
		}
		return null;
	}
	
	public static HashMap<String,Object> getUserById(String id){
		WebApplicationContext wac = show.me.the.money.util.AppContextHolder.get();
		SessionFactory sf = (SessionFactory)wac.getBean("mySessionFactory");
		Session ss = null;
		try{
			ss = sf.openSession();
			Query q = ss.createQuery(hql);
			q.setString("uid", id);
		
			HashMap<String,Object> rec = (HashMap<String,Object>)q.uniqueResult();
			if(rec == null){
				logger.fatal("User [" + id + "] not found from database.");
				return null;
			}
			return rec;
		}
		catch(Exception e){
			return null;
		}
		finally{
			if(ss != null && ss.isOpen()){
				ss.close();
			}
		}
	}
	
	public static Document getUserXMLTemplate(HashMap<String,Object> rec){
	
		String [] pk = {fieldUserId,fieldUserName,fieldPassword,fieldRole,fieldVersion,"limit"};
		List<String> list = Arrays.asList(pk);
		
		Document doc = DocumentHelper.createDocument();
		Element  root = doc.addElement("user");
		
		root.addAttribute("id", String.valueOf(rec.get(fieldUserId)));
		root.addAttribute("name", String.valueOf(rec.get(fieldUserName)));
		root.addAttribute("password", String.valueOf(rec.get(fieldPassword)));
		root.addAttribute("version", String.valueOf(rec.get("userVersion")));
		
		Element props = root.addElement("proptities");
		Schema sc = SchemaController.instance().getSchema(entryName);
		
		for(Iterator<String> it = rec.keySet().iterator();it.hasNext();){
			String pName = it.next();
			Object obj = rec.get(pName);
			if(obj == null ||list.contains(pName)){
				continue;
			}			
			String pValue = String.valueOf(obj);	
			
			Element prop = props.addElement("p");
			prop.addAttribute("name", pName);
			prop.setText(pValue);
			
			SchemaItem si = sc.item(pName);		
			if(si != null && si.isCodedValue()){
				Element exProp = props.addElement("p");
				exProp.addAttribute("name",pName + "_text");
				exProp.setText(si.getDisplayValue(pValue));
			}
		}
		Element rs = root.addElement("roles");	
		String roleId = (String)rec.get(fieldRole);
		if(StringUtils.isEmpty(roleId)){
			return null;
		}
		String[] roles = roleId.split(",");
		for(int i=0; i<roles.length; i++){
			Element r = rs.addElement("role");
			r.addAttribute("id",roles[i]);
		}
		
		return doc;
	}
	
	public static boolean resetPassword(String uid,String newPsw,String ver){
		//newPsw = MD5StringUtil.MD5Encode(newPsw);
		WebApplicationContext wac = show.me.the.money.util.AppContextHolder.get();
		SessionFactory sf = (SessionFactory)wac.getBean("mySessionFactory");		
		StringBuffer hql = new StringBuffer();
		hql.append("update ").append(entryName)
			.append(" set ").append(fieldPassword)
				.append("='").append(newPsw).append("',")
				.append(fieldVersion).append("='").append(ver).append("'")
					.append(" where ").append(fieldUserId).append("='").append(uid).append("'");
		Session ss = null;
		try{
			ss = sf.openSession();
			ss.beginTransaction();
			int q = ss.createQuery(hql.toString()).executeUpdate();
			ss.getTransaction().commit();
			return q == 1;
		}
		catch(Exception e){
			return false;
		}
		finally{
			if(ss != null && ss.isOpen()){
				ss.close();
			}
		}		
	}
	
	public static QueryResult userQuery(String exp, Context ctx){		
		Schema sc = SchemaController.instance().getSchema(entryName);
		if(sc == null){
			logger.error("user NoSuchSchema");
			return null;
		}
		SimpleDAO dao = null;
		try {
			//exp = exp.replace("\'", "\"");
			List queryCnd = jsonMapper.readValue(exp, List.class);
			dao = new SimpleDAO(sc,ctx);
			QueryResult qr = dao.find(queryCnd);
			return qr;
		}catch(Exception e){
			logger.error(e.getMessage());
			return null;
		}finally{
			//close(dao);
		}
	}
	
	public static HashMap<String,Object> saveUser(LinkedHashMap<String, Object> data, Context ctx){	
		String op = (String)data.get("op");
		if(op == null){
			op = "create";
		}
		Schema sc = SchemaController.instance().getSchema(entryName);
		if(sc == null){
			logger.error("user NoSuchSchema");
			return null;
		}
		SimpleDAO dao = null;
		try {
			HashMap<String,Object> genValues = null;
			dao = new SimpleDAO(sc,ctx);
			//dao.beginTransaction();
			if("create".equals(op)){
				genValues = dao.create(data);
			}else{
				genValues = dao.update(data);				
			}
			//dao.commitTransaction();
			return genValues;

		}catch(Exception e){
			logger.error(e.getMessage());
			try {
				dao.rollbackTransaction();
			} catch (DataAccessException e1) {
				return null;
			}
			return null;
		}finally{
			//close(dao);
		}		
	}
	
	public static HashMap<String,Object> loadUser(String id, Context ctx){
		Schema sc = SchemaController.instance().getSchema(entryName);
		if(sc == null){
			logger.error("user NoSuchSchema");
			return null;
		}
		SimpleDAO dao = null;
		try {
			dao = new SimpleDAO(sc,ctx);
			HashMap<String,Object> rec = dao.load(fieldUserId, id);
			if(rec == null){
				return null;
			}
			HashMap<String,Object> clone = (HashMap<String,Object>)rec.clone();
			dao.marshallRecord(clone);
			return clone;
		}catch(Exception e){
			logger.error(e.getMessage());
			return null;
		}finally{
			//close(dao);
		}
	}
	
	public static HashMap<String,Object> removeUser(String id, Context ctx){
		HashMap<String,Object> rec = new HashMap<String,Object>();
		Schema sc = SchemaController.instance().getSchema(entryName);
		if(sc == null){
			logger.error("user NoSuchSchema");
			return null;
		}
		SimpleDAO dao = null;
		try {
			dao = new SimpleDAO(sc,ctx);
			dao.beginTransaction();
			int effectCount = dao.removeByFieldValue(fieldUserId, id);
			dao.commitTransaction();
			rec.put("effectCount", effectCount);
			return rec;
		}catch(Exception e){
			logger.error(e.getMessage());
			try {
				dao.rollbackTransaction();
			} catch (DataAccessException e1) {
				return null;
			}
			return null;
		}finally{
			//close(dao);
		}
	}
	
	public static Set<String> getRecordCount(String id) {
		Set<String> s = new HashSet<String>();
		WebApplicationContext wac = AppContextHolder.get();
		SessionFactory sf = (SessionFactory)wac.getBean("mySessionFactory");
		HibernateTemplate ht = new HibernateTemplate(sf);
		StringBuffer hql = new StringBuffer();
	    hql.append("select ").append(fieldUserId).append(" from ").append(entryName).append(" where status='0' and ','||")
             .append(fieldRole).append("||',' like '%,").append(id).append(",%'");
	    try{
	        List ls = ht.find(hql.toString());
	        if(ls.size() > 0){
	        	 s.addAll(ls);
	        }       
	    }catch(Exception e){
	        logger.error((new StringBuilder("get[ ")).append(id).append(" ] count falied:").append(e.getMessage()).toString());
	    }
		return s;
	}
	
	private static void close(SimpleDAO dao){
	    if(dao != null){
		   try {
			  dao.destroy();
		   }catch (DataAccessException e) {
			  logger.error("DaoDestroyFailed:" + e.getMessage());
		   }
	    }
	}
}
